//////////
// 逻辑 and/or/not

#include "../basic/operator.h"

Cell* op_and0(Scheme *sc) {
	if (sc->code == &g_nil) {
		sc->returnValue = &g_true;
		return pop_callstack(sc);
	}
	push_callstack(sc, cell_op_and1, &g_nil, cdr(sc->code));
	sc->code = car(sc->code);
	sc->op = cell_op_eval;
	return &g_true;
}

Cell* op_and1(Scheme *sc) {
	if (is_false(sc->returnValue))
		return pop_callstack(sc);
	else if (sc->code == &g_nil)
		return pop_callstack(sc);
	else {
		push_callstack(sc, cell_op_and1, &g_nil, cdr(sc->code));
		sc->code = car(sc->code);
		sc->op = cell_op_eval;
		return &g_true;
	}
}

Cell* op_or0(Scheme *sc) {
	if (sc->code == &g_nil){
		sc->returnValue = &g_false;
		return pop_callstack(sc);
	}
	push_callstack(sc, cell_op_or1, &g_nil, cdr(sc->code));
	sc->code = car(sc->code);
	sc->op = cell_op_eval;
	return &g_true;
}

Cell* op_or1(Scheme *sc) {
	if (is_true(sc->returnValue))
		return pop_callstack(sc);
	else if (sc->code == &g_nil)
		return pop_callstack(sc);
	else {
		push_callstack(sc, cell_op_or1, &g_nil, cdr(sc->code));
		sc->code = car(sc->code);
		sc->op = cell_op_eval;
		return &g_true;
	}
}

// (not x)
Cell* op_not(Scheme *sc) {
	int istrue = (is_false(first(sc->args)));
	sc->returnValue = ((istrue) ? &g_true : &g_false);
	return pop_callstack(sc);
}

void init_logic_operators(Scheme *sc) {
	ADD_OPERATOR(sc, "$and0", and0);
	ADD_OPERATOR(sc, "$and1", and1);
	ADD_OPERATOR(sc, "$or0", or0);
	ADD_OPERATOR(sc, "$or1", or1);
	ADD_OPERATOR(sc, "not", not);

	ADD_SYNTAX(sc, "and", and0);
	ADD_SYNTAX(sc, "or", or0);
}
